/**
 *	@file    hsHash.c
 *	@version 8e6f0e1 (HEAD -> master)
 *
 *	"Native" handshake hash.
 */
/*
 *	Copyright (c) 2013-2016 INSIDE Secure Corporation
 *	Copyright (c) PeerSec Networks, 2002-2011
 *	All Rights Reserved
 *
 *	The latest version of this code is available at http://www.matrixssl.org
 *
 *	This software is open source; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This General Public License does NOT permit incorporating this software
 *	into proprietary programs.  If you are unable to comply with the GPL, a
 *	commercial license for this software may be purchased from INSIDE at
 *	http://www.insidesecure.com/
 *
 *	This program is distributed in WITHOUT ANY WARRANTY; without even the
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *	See the GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *	http://www.gnu.org/copyleft/gpl.html
 */

#include "matrixsslApi.h"

#define FINISHED_LABEL_SIZE	15
#define LABEL_CLIENT		"client finished"
#define LABEL_SERVER		"server finished"
/******************************************************************************/
/**
	Initialize the SHA1 and MD5 hash contexts for the handshake messages.
	The handshake hashes are used in 3 messages in TLS:
	ClientFinished, ServerFinished and ClientCertificateVerify.
	The version of TLS affects which hashes are used for the Finished messages.
	TLS 1.2 allows a different hash algorithm for the CertificatVerify message
	than is used by the Finished messages, determined by the
	Signature Algorithms extension.
	Multiple handshake hash contexts must be maintained until the handshake has
	progressed enough to determine the negotiated TLS version and whether or
	not Client Authentication is to be performed. Also, if USE_ONLY_TLS_1_2 is
	defined at compile time, or USE_CLIENT_AUTH is undefined at compile time,
	the potential runtime combinations are reduced.
	The various algorithms are used as follows (+ means concatenation):
		Client and Server Finished messages
			< TLS 1.2 - MD5+SHA1
			TLS 1.2 - SHA256
		Client CertificateVerify message.
			< TLS 1.2 - MD5+SHA1
			TLS 1.2 - One of the hashes present in the union of the 
			SignatureAlgorithms Client extension and the CertificateRequest
			message from the server. At most this is the set
			{SHA1,SHA256,SHA384,SHA512}.
	@return < 0 on failure.
	@param[in,out] ssl TLS context
*/
int32_t sslInitHSHash(ssl_t *ssl)
{
#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		/* Don't allow CLIENT_HELLO message retransmit to reset hash */
		if (ssl->retransmit) {
			return 0;
		}
	}
#endif /* USE_DTLS */

#ifndef USE_ONLY_TLS_1_2
	psMd5Sha1Init(&ssl->sec.msgHashMd5Sha1);
#endif

#ifdef USE_TLS_1_2
	psSha256Init(&ssl->sec.msgHashSha256);
 #ifdef USE_SHA1
	psSha1Init(&ssl->sec.msgHashSha1);
 #endif
 #ifdef USE_SHA384
	psSha384Init(&ssl->sec.msgHashSha384);
 #endif
 #ifdef USE_SHA512
	psSha512Init(&ssl->sec.msgHashSha512);
 #endif
#endif

	return 0;
}

/******************************************************************************/
/**
	Add the given data to the running hash of the handshake messages.
	@param[in,out] ssl TLS context
	@param[in] in Pointer to handshake data to hash.
	@param[in] len Number of bytes of handshake data to hash.
	@return < 0 on failure.
*/
int32_t sslUpdateHSHash(ssl_t *ssl, const unsigned char *in, uint16_t len)
{

#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		/* Don't update handshake hashes on resends.  Already been through here */
		if (ssl->retransmit) {
			return 0;
		}
	}
#endif /* USE_DTLS */

#ifdef USE_TLS_1_2
	/* Keep a running total of each for greatest RFC support when it comes
		to the CertificateVerify message.  Although, trying to be smart
		about MD5 and SHA-2 based on protocol version. */
	if ((ssl->majVer == 0 && ssl->minVer == 0) ||
#ifdef USE_DTLS
			ssl->minVer == DTLS_1_2_MIN_VER	||
#endif
			ssl->minVer == TLS_1_2_MIN_VER) {
		psSha256Update(&ssl->sec.msgHashSha256, in, len);
 #ifdef USE_SHA1
		psSha1Update(&ssl->sec.msgHashSha1, in, len);
 #endif
 #ifdef USE_SHA384
		psSha384Update(&ssl->sec.msgHashSha384, in, len);
 #endif
 #ifdef USE_SHA512
		psSha512Update(&ssl->sec.msgHashSha512, in, len);
 #endif
	}
#endif

#ifndef USE_ONLY_TLS_1_2
	/* Below TLS 1.2, the hash is always the md5sha1 hash. If we negotiate
		to TLS 1.2 and need sha1, we use just that part of the md5Sha1. */
//TODO	if (ssl->reqMinVer == 0 || ssl->minVer != TLS_1_2_MIN_VER) {
	psMd5Sha1Update(&ssl->sec.msgHashMd5Sha1, in, len);

#endif

	return 0;
}

#ifdef USE_TLS_1_2
/*	Functions necessary to deal with needing to keep track of both SHA-1
	and SHA-256 handshake hash states.  FINISHED message will always be
	SHA-256 but client might be sending SHA-1 CertificateVerify message */
 #if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
  #ifdef USE_SHA1
int32 sslSha1RetrieveHSHash(ssl_t *ssl, unsigned char *out)
{
	memcpy(out, ssl->sec.sha1Snapshot, SHA1_HASH_SIZE);
	return SHA1_HASH_SIZE;
}
  #endif
  #ifdef USE_SHA384
int32 sslSha384RetrieveHSHash(ssl_t *ssl, unsigned char *out)
{
	memcpy(out, ssl->sec.sha384Snapshot, SHA384_HASH_SIZE);
	return SHA384_HASH_SIZE;
}
  #endif
  #ifdef USE_SHA512
int32 sslSha512RetrieveHSHash(ssl_t *ssl, unsigned char *out)
{
	memcpy(out, ssl->sec.sha512Snapshot, SHA512_HASH_SIZE);
	return SHA512_HASH_SIZE;
}
  #endif
 #endif /* USE_SERVER_SIDE_SSL && USE_CLIENT_AUTH */

 #if defined(USE_CLIENT_SIDE_SSL) && defined(USE_CLIENT_AUTH)
  #ifdef USE_SHA1
/*	It is possible the certificate verify message wants a non-SHA256 hash */
void sslSha1SnapshotHSHash(ssl_t *ssl, unsigned char *out)
{
	psSha1Final(&ssl->sec.msgHashSha1, out);
}
  #endif
  #ifdef USE_SHA384
void sslSha384SnapshotHSHash(ssl_t *ssl, unsigned char *out)
{
	psSha384_t sha384;

	/* SHA384 must copy the context because it could be needed again for
		final handshake hash.  SHA1 doesn't need this because it will
		not ever be used again after this client auth one-off */
	psSha384Sync(&ssl->sec.msgHashSha384, 0);
	sha384 = ssl->sec.msgHashSha384;
	psSha384Final(&sha384, out);
}
  #endif
  #ifdef USE_SHA512
void sslSha512SnapshotHSHash(ssl_t *ssl, unsigned char *out)
{
	psSha512_t sha512;

	/* SHA512 must copy the context because it could be needed again for
		final handshake hash.  SHA1 doesn't need this because it will
		not ever be used again after this client auth one-off */
	psSha512Sync(&ssl->sec.msgHashSha512, 0);
	sha512 = ssl->sec.msgHashSha512;
	psSha512Final(&sha512, out);
}
  #endif
 #endif /* USE_CLIENT_SIDE_SSL && USE_CLIENT_AUTH */
#endif /* USE_TLS_1_2 */

#ifdef USE_TLS
/******************************************************************************/
/*
	TLS handshake hash computation
*/
static int32_t tlsGenerateFinishedHash(ssl_t *ssl,
 #ifndef USE_ONLY_TLS_1_2
				psMd5Sha1_t *md5sha1,
 #endif
 #ifdef USE_TLS_1_2
 #ifdef USE_SHA1
				psSha1_t *sha1,
 #endif
 #ifdef USE_SHA256
				psSha256_t *sha256,
 #endif
 #ifdef USE_SHA384
				psSha384_t *sha384,
 #endif
 #ifdef USE_SHA512
				psSha512_t *sha512,
 #endif
 #endif /* USE_TLS_1_2 */
				unsigned char *masterSecret,
				unsigned char *out, int32 senderFlag)
{
	unsigned char	tmp[FINISHED_LABEL_SIZE + SHA384_HASH_SIZE];

#ifndef USE_ONLY_TLS_1_2
	psMd5Sha1_t md5sha1_backup;
#endif
#ifdef USE_SHA1
	psSha1_t sha1_backup;
#endif
#ifdef USE_SHA256
	psSha256_t sha256_backup;
#endif
#ifdef USE_SHA384
	psSha384_t sha384_backup;
#endif
#ifdef USE_SHA512
	psSha512_t sha512_backup;
#endif
/*
	In each branch: Use a backup of the message hash-to-date because we don't
	want to destroy the state of the handshaking until truly complete
*/

	if (senderFlag >= 0) {
		memcpy(tmp, (senderFlag & SSL_FLAGS_SERVER) ? LABEL_SERVER : LABEL_CLIENT,
			FINISHED_LABEL_SIZE);
 #ifdef USE_TLS_1_2
		if (ssl->flags & SSL_FLAGS_TLS_1_2) {
			if (ssl->cipher->flags & CRYPTO_FLAGS_SHA3) {
  #ifdef USE_SHA384
				psSha384Cpy(&sha384_backup, sha384);
				psSha384Final(&sha384_backup, tmp + FINISHED_LABEL_SIZE);
				return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp,
					FINISHED_LABEL_SIZE + SHA384_HASH_SIZE, out,
					TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA3);
  #endif
			} else {
				psSha256Cpy(&sha256_backup, sha256);
				psSha256Final(&sha256_backup, tmp + FINISHED_LABEL_SIZE);
				return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp,
					FINISHED_LABEL_SIZE + SHA256_HASH_SIZE, out,
					TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA2);
			}
  #ifndef USE_ONLY_TLS_1_2
		} else {
			psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
			psMd5Sha1Final(&md5sha1_backup, tmp + FINISHED_LABEL_SIZE);
			return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp,
				FINISHED_LABEL_SIZE + MD5SHA1_HASHLEN,
				out, TLS_HS_FINISHED_SIZE);
  #endif
		}
 #else
		psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
		psMd5Sha1Final(&md5sha1_backup, tmp + FINISHED_LABEL_SIZE);
		return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp,
			FINISHED_LABEL_SIZE + MD5SHA1_HASHLEN,
			out, TLS_HS_FINISHED_SIZE);
 #endif
	} else {
		/* Overloading this function to handle the client auth needs of
			handshake hashing. */
 #ifdef USE_TLS_1_2
		if (ssl->flags & SSL_FLAGS_TLS_1_2) {
			psSha256Cpy(&sha256_backup, sha256);
			psSha256Final(&sha256_backup, out);
  #if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
			/* Check to make sure we are a server because clients come
				through here as well and they do not need to snapshot any
				hashes because they are in a write state during the
				CERTIFICATE_VERIFY creation.  So if they detect a non-default 
				in digest, they just run the sslSha384SnapshotHSHash family
				of functions.  Servers really do have to save aside the
				snapshots beause the CERTIFICATE_VERIFY is a parse and so the 
				handshake hash is being set aside for all possible combos
				here so the sslSha384RetrieveHSHash can fetch.  Previous
				versions were not testing for SERVER here so clients were
				running digest operations that were not needed in client auth */
			if (ssl->flags & SSL_FLAGS_SERVER) {
   #ifdef USE_SHA384
				psSha384Cpy(&sha384_backup, sha384);
				psSha384Final(&sha384_backup, ssl->sec.sha384Snapshot);
   #endif
   #ifdef USE_SHA512
				psSha512Cpy(&sha512_backup, sha512);
				psSha512Final(&sha512_backup, ssl->sec.sha512Snapshot);
   #endif
   #ifdef USE_SHA1
				psSha1Cpy(&sha1_backup, sha1);
				psSha1Final(&sha1_backup, ssl->sec.sha1Snapshot);
   #endif
			}
  #endif
			return SHA256_HASH_SIZE;
  #ifndef USE_ONLY_TLS_1_2
		} else {
			psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
			psMd5Sha1Final(&md5sha1_backup, out);
			return MD5SHA1_HASHLEN;
  #endif
		}
 #else
/*
		The handshake snapshot for client authentication is simply the
		appended MD5 and SHA1 hashes
*/
		psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
		psMd5Sha1Final(&md5sha1_backup, out);
		return MD5SHA1_HASHLEN;
 #endif /* USE_TLS_1_2 */
	}
	return PS_FAILURE; /* Should not reach this */
}
#endif /* USE_TLS */


/* The extended master secret computation uses a handshake hash */
int32_t extMasterSecretSnapshotHSHash(ssl_t *ssl, unsigned char *out,
			uint32 *outLen)
{
#ifndef USE_ONLY_TLS_1_2
	psMd5Sha1_t			md5sha1;
#endif
#ifdef USE_SHA256
	psSha256_t			sha256;
#endif
#ifdef USE_SHA384
	psSha384_t			sha384;
#endif

/*
	Use a backup of the message hash-to-date because we don't want
	to destroy the state of the handshaking until truly complete
*/

	*outLen = 0;
	
#ifdef USE_TLS_1_2
	if (ssl->flags & SSL_FLAGS_TLS_1_2) {
		if (ssl->cipher->flags & CRYPTO_FLAGS_SHA3) {
#ifdef USE_SHA384
			psSha384Cpy(&sha384, &ssl->sec.msgHashSha384);
			psSha384Final(&sha384, out);
			*outLen = SHA384_HASH_SIZE;
#endif
		} else {
			psSha256Cpy(&sha256, &ssl->sec.msgHashSha256);
			psSha256Final(&sha256, out);
			*outLen = SHA256_HASH_SIZE;
		}
#ifndef USE_ONLY_TLS_1_2
	} else {
		psMd5Sha1Cpy(&md5sha1, &ssl->sec.msgHashMd5Sha1);
		psMd5Sha1Final(&md5sha1, out);
		*outLen = MD5SHA1_HASHLEN;
#endif
	}
#else /* no TLS 1.2 */
	psMd5Sha1Cpy(&md5sha1, &ssl->sec.msgHashMd5Sha1);
	psMd5Sha1Final(&md5sha1, out);
	*outLen = MD5SHA1_HASHLEN;
#endif
	
	return *outLen;
}


/******************************************************************************/
/*
	Snapshot is called by the receiver of the finished message to produce
	a hash of the preceeding handshake messages for comparison to incoming
	message.
*/
int32_t sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag)
{
	int32				len = PS_FAILURE;

#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		/* Don't allow FINISHED message retransmit to re-calc hash */
		if (ssl->retransmit) {
			memcpy(out, ssl->hsSnapshot, ssl->hsSnapshotLen);
			return ssl->hsSnapshotLen;
		}
	}
#endif /* USE_DTLS */

#ifdef USE_TLS
	if (ssl->flags & SSL_FLAGS_TLS) {
		len = tlsGenerateFinishedHash(ssl,
 #ifndef USE_ONLY_TLS_1_2
			&ssl->sec.msgHashMd5Sha1,
 #endif
 #ifdef USE_TLS_1_2
 #ifdef USE_SHA1
			&ssl->sec.msgHashSha1,
 #endif
 #ifdef USE_SHA256
			&ssl->sec.msgHashSha256,
 #endif
 #ifdef USE_SHA384
			&ssl->sec.msgHashSha384,
 #endif
 #ifdef USE_SHA512
			&ssl->sec.msgHashSha512,
 #endif
 #endif /* USE_TLS_1_2 */
			ssl->sec.masterSecret, out, senderFlag);

 #ifndef DISABLE_SSLV3
	} else {
		len = sslGenerateFinishedHash(&ssl->sec.msgHashMd5Sha1,
			ssl->sec.masterSecret, out, senderFlag);
 #endif /* DISABLE_SSLV3 */
	}
#endif /* USE_TLS */

#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		if (len > 0) {
			memcpy(ssl->hsSnapshot, out, len);
			ssl->hsSnapshotLen = len;
		}
	}
#endif /* USE_DTLS */
	return len;
}

/******************************************************************************/

